package com.teamide.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class ResourceUtil {

	public static ClassLoader getCurrentClassLoader() {

		return Thread.currentThread().getContextClassLoader();
	}

	public static ClassLoader getClassLoader(ClassLoader loader) {

		if (loader == null) {
			return Thread.currentThread().getContextClassLoader();
		}
		return loader;
	}

	public static InputStream load(String name) {

		return load(null, name);
	}

	public static InputStream load(ClassLoader loader, String name) {

		loader = getClassLoader(loader);
		InputStream stream = loader.getResourceAsStream(name);
		if (stream == null) {
			// 读取Spring Boot下的配置文件
			stream = loader.getResourceAsStream("BOOT-INF/classes/" + name);
		}
		if (stream == null) {
			// 读取META-INF下的配置文件
			stream = loader.getResourceAsStream("META-INF/resources/" + name);
		}
		return stream;
	}

	public static URL loadURL(String name) {

		return loadURL(null, name);
	}

	public static URL loadURL(ClassLoader loader, String name) {

		loader = getClassLoader(loader);
		URL url = loader.getResource(name);
		if (url == null) {
			// 读取Spring Boot下的配置文件
			url = loader.getResource("BOOT-INF/classes/" + name);
		}
		if (url == null) {
			// 读取META-INF下的配置文件
			url = loader.getResource("META-INF/resources/" + name);
		}
		return url;
	}

	public static URL getURL(String name) {

		return getURL(null, name);
	}

	public static URL getURL(ClassLoader loader, String name) {

		loader = getClassLoader(loader);
		return loader.getResource(name);
	}

	public static Set<URL> getURLs(String pack) throws IOException {

		return getURLs(null, pack);

	}

	public static Set<URL> getURLs(ClassLoader loader, String pack) throws IOException {

		loader = getClassLoader(loader);
		Set<URL> urls = new HashSet<URL>();
		if (null == pack) {
			return urls;
		}
		Enumeration<URL> enumeration = loader.getResources(pack);
		if (enumeration != null) {
			while (enumeration.hasMoreElements()) {
				URL url = enumeration.nextElement();
				urls.add(url);
			}
		}
		return urls;

	}

	public static Set<Class<?>> loadClass(String pack) throws IOException {

		return loadClass(null, pack);

	}

	public static Set<Class<?>> loadClass(ClassLoader loader, String pack) throws IOException {

		loader = getClassLoader(loader);
		Set<Class<?>> classes = new HashSet<Class<?>>();
		Map<URL, byte[]> map = loadBytes(pack);
		Set<URL> urls = getURLs(loader, pack);
		for (URL url : map.keySet()) {
			String name = null;
			String urlPath = url.getPath();
			int index = urlPath.lastIndexOf("!/");
			if (index > 0) {
				urlPath = urlPath.substring(index + 2);
			}
			for (URL u : urls) {
				String uPath = u.getPath();
				index = uPath.lastIndexOf("!/");
				if (index > 0) {
					uPath = uPath.substring(index + 2);
				}
				if (urlPath.startsWith(uPath)) {
					String url_path = urlPath;
					String u_path = uPath;
					if (!u_path.endsWith("/")) {
						u_path += "/";
					}
					name = url_path.substring(u_path.length() - pack.length() - 1);
				}
			}
			if (StringUtil.isEmpty(name) || !name.endsWith(".class")) {
				continue;
			}
			name = name.replaceAll("/", ".");
			name = name.substring(0, name.length() - 6);
			try {
				Class<?> clazz = loader.loadClass(name);
				classes.add(clazz);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		return classes;

	}

	public static Map<URL, byte[]> loadBytes(String pack) throws IOException {

		return loadBytes(null, pack);
	}

	public static Map<URL, byte[]> loadBytes(ClassLoader loader, String pack) throws IOException {

		Map<URL, byte[]> map = new HashMap<URL, byte[]>();
		Set<URL> urls = getURLs(loader, pack);
		if (urls != null) {
			for (URL url : urls) {
				map.putAll(loadBytesByURL(loader, url));
			}
		}
		return map;

	}

	public static Map<URL, byte[]> loadBytesByURL(ClassLoader loader, URL url) throws IOException {

		loader = getClassLoader(loader);

		Map<URL, byte[]> map = new HashMap<URL, byte[]>();
		if (url == null) {
			return map;
		}
		// 得到协议的名称
		String protocol = url.getProtocol();
		// 如果是以文件的形式保存在服务器上
		if ("file".equals(protocol)) {
			// 获取包的物理路径
			String folder = URLDecoder.decode(url.getPath(), "UTF-8");
			Map<URL, byte[]> map_ = FileUtil.readAllFiles(folder);
			for (URL key : map_.keySet()) {
				if (key.getPath().indexOf(folder) < 0) {
					continue;
				}
				map.put(key, map_.get(key));
			}
		} else if ("jar".equals(protocol)) {
			String path = url.getPath();
			int index = path.lastIndexOf("jar!/");
			if (index > 0) {
				String pack = path.substring(index + 5);
				if (pack.indexOf("!/") >= 0) {
					pack = pack.substring(pack.indexOf("!/") + 2);
				}
				Map<String, byte[]> map_ = JarEntryUtil.read(url);
				for (String key : map_.keySet()) {
					if (key.indexOf(pack) != 0) {
						continue;
					}
					URL u = loader.getResource(key);
					map.put(u, map_.get(key));
				}
			}
		}
		return map;
	}

	/**
	 * 指定类是否被提供，使用默认ClassLoader<br>
	 * 方法尝试加载指定类名的类，如果加载失败返回false<br>
	 * 加载失败的原因可能是此类不存在或其关联引用类不存在
	 * 
	 * @param className
	 *            类名
	 * @return 是否被提供
	 */
	public static boolean isPresent(String className) {

		return isPresent(className, null);
	}

	/**
	 * 指定类是否被提供<br>
	 * 方法尝试加载指定类名的类，如果加载失败返回false<br>
	 * 加载失败的原因可能是此类不存在或其关联引用类不存在
	 * 
	 * @param className
	 *            类名
	 * @param loader
	 *            类型加载器
	 * @return 是否被提供
	 */
	public static boolean isPresent(String className, ClassLoader loader) {

		try {
			loader = getClassLoader(loader);
			loader.loadClass(className);
			return true;
		} catch (Throwable ex) {
			return false;
		}
	}

}
